﻿namespace JanusLibAing
{
    using System;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Text;

    internal static class NativeMethods
    {
        #region Misc

        public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        #endregion

        #region User

        public const int MAX_PATH = 260;

        [SecurityCritical, SuppressUnmanagedCodeSecurity, DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int nMsg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int nMsg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);

        #endregion

        #region Shell

        #region Malloc

        [ComImport, SuppressUnmanagedCodeSecurity, Guid("00000002-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IMalloc
        {
            [PreserveSig]
            IntPtr Alloc(int cb);
            [PreserveSig]
            IntPtr Realloc(IntPtr pv, int cb);
            [PreserveSig]
            void Free(IntPtr pv);
            [PreserveSig]
            int GetSize(IntPtr pv);
            [PreserveSig]
            int DidAlloc(IntPtr pv);
            [PreserveSig]
            void HeapMinimize();
        }

        public static IMalloc GetSHMalloc()
        {
            IMalloc[] ppMalloc = new IMalloc[1];
            SHGetMalloc(ppMalloc);
            return ppMalloc[0];
        }

        [DllImport("shell32.dll")]
        private static extern int SHGetMalloc([Out, MarshalAs(UnmanagedType.LPArray)] IMalloc[] ppMalloc);

        #endregion

        [StructLayout(LayoutKind.Sequential)]
        public struct BROWSEINFO
        {
            /// <summary>
            /// Handle to the owner window for the dialog box.
            /// </summary>
            public IntPtr HwndOwner;

            /// <summary>
            /// Pointer to an item identifier list (PIDL) specifying the 
            /// location of the root folder from which to start browsing.
            /// </summary>
            public IntPtr Root;

            /// <summary>
            /// Address of a buffer to receive the display name of the
            /// folder selected by the user.
            /// </summary>
            [MarshalAs(UnmanagedType.LPWStr)]
            public string DisplayName;

            /// <summary>
            /// Address of a null-terminated string that is displayed 
            /// above the tree view control in the dialog box.
            /// </summary>
            [MarshalAs(UnmanagedType.LPWStr)]
            public string Title;

            /// <summary>
            /// Flags specifying the options for the dialog box.
            /// </summary>
            public uint Flags;

            /// <summary>
            /// Address of an application-defined function that the
            /// dialog box calls when an event occurs.
            /// </summary>
            [MarshalAs(UnmanagedType.FunctionPtr)]
            public WndProc Callback;

            /// <summary>
            /// Application-defined value that the dialog box passes to 
            /// the callback function
            /// </summary>
            public int LParam;

            /// <summary>
            /// Variable to receive the image associated with the selected folder.
            /// </summary>
            public int Image;
        }

        public const int BFFM_INITIALIZED = 1;
        public const int BFFM_SELCHANGED = 2;
        public const int BFFM_VALIDATEFAILEDA = 3; // lParam:szPath ret:1(cont),0(EndDialog)
        public const int BFFM_VALIDATEFAILEDW = 4; // lParam:wzPath ret:1(cont),0(EndDialog)
        public const int BFFM_IUNKNOWN = 5; // provides IUnknown to client. lParam: IUnknown*

        public const int WM_USER = 1024;
        public const int BFFM_ENABLEOK = (WM_USER + 101);
        public const int BFFM_SETSELECTIONW = (WM_USER + 103);
        public const int BFFM_SETSTATUSTEXTW = (WM_USER + 104);
        public const int BFFM_SETOKTEXT = (WM_USER + 105); // Unicode only
        public const int BFFM_SETEXPANDED = (WM_USER + 106); // Unicode only

        [StructLayout(LayoutKind.Explicit)]
        public struct STRRET
        {
            /// <summary>
            /// One of the STRRET_* values
            /// </summary>
            [FieldOffset(0)]
            public STRRET_TYPE uType;

            /// <summary>
            /// must be freed by caller of GetDisplayNameOf
            /// </summary>
            [FieldOffset(4)]
            public IntPtr pOleStr;

            /// <summary>
            /// NOT USED
            /// </summary>
            [FieldOffset(4)]
            public IntPtr pStr;

            /// <summary>
            /// Offset into SHITEMID
            /// </summary>
            [FieldOffset(4)]
            public uint uOffset;

            /// <summary>
            /// Buffer to fill in (ANSI)
            /// </summary>
            [FieldOffset(4)]
            public IntPtr cStr;
        }

        public enum STRRET_TYPE : uint
        {
            /// <summary>
            /// Use STRRET.pOleStr
            /// </summary>
            STRRET_WSTR = 0x0000,
            /// <summary>
            /// Use STRRET.uOffset to Ansi
            /// </summary>
            STRRET_OFFSET = 0x0001,
            /// <summary>
            /// Use STRRET.cStr
            /// </summary>
            STRRET_CSTR = 0x0002,
        }

        [Flags]
        public enum FolderBrowserOptions
        {
            /// <summary>
            /// None.
            /// </summary>
            None = 0,
            /// <summary>
            /// For finding a folder to start document searching
            /// </summary>
            FolderOnly = 0x0001,
            /// <summary>
            /// For starting the Find Computer
            /// </summary>
            FindComputer = 0x0002,
            /// <summary>
            /// Top of the dialog has 2 lines of text for BROWSEINFO.lpszTitle and 
            /// one line if this flag is set.  Passing the message 
            /// BFFM_SETSTATUSTEXTA to the hwnd can set the rest of the text.  
            /// This is not used with BIF_USENEWUI and BROWSEINFO.lpszTitle gets
            /// all three lines of text.
            /// </summary>
            ShowStatusText = 0x0004,
            ReturnAncestors = 0x0008,
            /// <summary>
            /// Add an editbox to the dialog
            /// </summary>
            ShowEditBox = 0x0010,
            /// <summary>
            /// insist on valid result (or CANCEL)
            /// </summary>
            ValidateResult = 0x0020,
            /// <summary>
            /// Use the new dialog layout with the ability to resize
            /// Caller needs to call OleInitialize() before using this API
            /// </summary>
            UseNewStyle = 0x0040,
            UseNewStyleWithEditBox = (UseNewStyle | ShowEditBox),
            /// <summary>
            /// Allow URLs to be displayed or entered. (Requires BIF_USENEWUI)
            /// </summary>
            AllowUrls = 0x0080,
            /// <summary>
            /// Add a UA hint to the dialog, in place of the edit box. May not be
            /// combined with BIF_EDITBOX.
            /// </summary>
            ShowUsageHint = 0x0100,
            /// <summary>
            /// Do not add the "New Folder" button to the dialog.  Only applicable 
            /// with BIF_NEWDIALOGSTYLE.
            /// </summary>
            HideNewFolderButton = 0x0200,
            /// <summary>
            /// don't traverse target as shortcut
            /// </summary>
            GetShortcuts = 0x0400,
            /// <summary>
            /// Browsing for Computers.
            /// </summary>
            BrowseComputers = 0x1000,
            /// <summary>
            /// Browsing for Printers.
            /// </summary>
            BrowsePrinters = 0x2000,
            /// <summary>
            /// Browsing for Everything
            /// </summary>
            BrowseFiles = 0x4000,
            /// <summary>
            /// sharable resources displayed (remote shares, requires BIF_USENEWUI)
            /// </summary>
            BrowseShares = 0x8000
        }

        [DllImport("shell32")]
        public static extern int SHGetFolderLocation(IntPtr hwndOwner, Int32 nFolder, IntPtr hToken, uint dwReserved, out IntPtr ppidl);

        [DllImport("shell32")]
        public static extern int SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)]string pszName, IntPtr pbc, out IntPtr ppidl, uint sfgaoIn, out uint psfgaoOut);

        [DllImport("shell32", CharSet = CharSet.Unicode)]
        public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lbpi);

        [DllImport("shell32", CharSet = CharSet.Unicode)]
        public static extern bool SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath);

        #endregion
    }

}
